home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Entertainment / MacMud / Sockets / netdb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-17  |  11.3 KB  |  501 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    A more or less BSD compatable socket library for MacTCP
  3.  *    
  4.  *    Summer 1989, Tom Milligan, University of Toronto Computing Services
  5.  *
  6.  *
  7.  *    Internet name routines that every good unix program uses...
  8.  *
  9.  *        gethostbyname
  10.  *        gethostbyaddr
  11.  *        gethostname
  12.  *        getdomainname
  13.  *        inet_addr
  14.  *        inet_ntoa
  15.  *        getservbyname
  16.  *        getprotobyname
  17.  */
  18.  
  19. #include <types.h>
  20. #include <resources.h>
  21. #include <errors.h>
  22. #include <OSUtils.h> /* for SysBeep */
  23.  
  24. #include <sys/types.h>
  25. #include <sys/param.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <ctype.h>
  29. #include <netdb.h>
  30. #include <stdio.h>
  31. #include <errno.h>
  32. #include <arpa/nameser.h>
  33.  
  34. #include "tcpglue.h"
  35. #include "socket.internal.h"
  36.  
  37. int h_errno;
  38.  
  39. /*
  40.  *   Gethostbyname and gethostbyaddr each return a pointer to an
  41.  *   object with the following structure describing an Internet
  42.  *   host referenced by name or by address, respectively. This
  43.  *   structure contains the information obtained from the MacTCP
  44.  *   name server.
  45.  *
  46.  *   struct    hostent 
  47.  *   {
  48.  *        char *h_name;
  49.  *        char **h_aliases;
  50.  *        int  h_addrtype;
  51.  *        int  h_length;
  52.  *        char **h_addr_list;
  53.  *   };
  54.  *   #define   h_addr  h_addr_list[0]
  55.  *
  56.  *   The members of this structure are:
  57.  *
  58.  *   h_name       Official name of the host.
  59.  *
  60.  *   h_aliases    A zero terminated array of alternate names for the host.
  61.  *
  62.  *   h_addrtype   The type of address being  returned; always AF_INET.
  63.  *
  64.  *   h_length     The length, in bytes, of the address.
  65.  *
  66.  *   h_addr_list  A zero terminated array of network addresses for the host.
  67.  *
  68.  *   Error return status from gethostbyname and gethostbyaddr  is
  69.  *   indicated by return of a null pointer.  The external integer
  70.  *   h_errno may then  be checked  to  see  whether  this  is  a
  71.  *   temporary  failure  or  an  invalid  or  unknown  host.  The
  72.  *   routine herror  can  be  used  to  print  an error  message
  73.  *   describing the failure.  If its argument string is non-NULL,
  74.  *   it is printed, followed by a colon and a space.   The  error
  75.  *   message is printed with a trailing newline.
  76.  *
  77.  *   h_errno can have the following values:
  78.  *
  79.  *     HOST_NOT_FOUND  No such host is known.
  80.  *
  81.  *     TRY_AGAIN    This is usually a temporary error and
  82.  *                    means   that  the  local  server  did  not
  83.  *                    receive a response from  an  authoritative
  84.  *                    server.   A  retry at some later time may
  85.  *                    succeed.
  86.  *
  87.  *     NO_RECOVERY    Some unexpected server failure was encountered.
  88.  *                     This is a non-recoverable error.
  89.  *
  90.  *     NO_DATA        The requested name is valid but  does  not
  91.  *                    have   an IP  address;  this  is not  a
  92.  *                    temporary error. This means that the  name
  93.  *                    is known  to the name server but there is
  94.  *                    no address  associated  with  this  name.
  95.  *                    Another type of request to the name server
  96.  *                    using this domain name will result in  an
  97.  *                    answer;  for example, a mail-forwarder may
  98.  *                    be registered for this domain.
  99.  *                    (NOT GENERATED BY THIS IMPLEMENTATION)
  100.  */
  101.  
  102. static struct hostInfo macHost;
  103.  
  104. #define MAXALIASES 0
  105. static char *aliasPtrs[MAXALIASES+1] = {NULL};
  106. static ip_addr *addrPtrs[NUM_ALT_ADDRS+1];
  107.  
  108. static struct hostent  unixHost = 
  109. {
  110.     macHost.cname,
  111.     aliasPtrs,
  112.     AF_INET,
  113.     sizeof(ip_addr),
  114.     addrPtrs
  115. };
  116.  
  117. pascal void DNRDone(hostinfoPtr,done)
  118.     struct hostInfo *hostinfoPtr;
  119.     Boolean *done;
  120. {
  121. #pragma unused(hostinfoPtr)
  122.     *done = true;
  123. }
  124.  
  125. struct hostent *
  126. gethostbyname(name)
  127.     char *name;
  128. {
  129.     Boolean done;
  130.     int i;
  131.     
  132. #if    NETDB_DEBUG >= 3
  133.     dprintf("gethostbyname: '%s'\n",name);
  134. #endif
  135.  
  136.     for (i=0; i<NUM_ALT_ADDRS; i++)
  137.         macHost.addr[i] = 0;
  138.     done = false;
  139.     if (StrToAddr(name,&macHost,DNRDone,&done) == cacheFault)
  140.     {
  141. #if NETDB_DEBUG >= 5
  142.         dprintf("gethostbyname: spinning\n");
  143. #endif
  144.         while(! done)
  145.         {
  146.             if (spinroutine != NULL)
  147.                 (*spinroutine)();
  148.         }
  149. #if NETDB_DEBUG >= 5
  150.         dprintf("gethostbyname: done spinning\n");
  151. #endif
  152.     }
  153.     switch (macHost.rtnCode)
  154.     {
  155.         case noErr: break;
  156.         
  157.         case nameSyntaxErr:    h_errno = HOST_NOT_FOUND;    return(NULL);
  158.         case cacheFault:    h_errno = NO_RECOVERY;        return(NULL);
  159.         case noResultProc:    h_errno = NO_RECOVERY;        return(NULL);
  160.         case noNameServer:    h_errno = HOST_NOT_FOUND;    return(NULL);
  161.         case authNameErr:    h_errno = HOST_NOT_FOUND;    return(NULL);
  162.         case noAnsErr:        h_errno = TRY_AGAIN;        return(NULL);
  163.         case dnrErr:        h_errno = NO_RECOVERY;        return(NULL);
  164.         case outOfMemory:    h_errno = TRY_AGAIN;        return(NULL);
  165.         case notOpenErr:    h_errno = NO_RECOVERY;        return(NULL);
  166.         default:            h_errno = NO_RECOVERY;        return(NULL);
  167.     }
  168.     
  169. #if NETDB_DEBUG >= 5
  170.     dprintf("gethostbyname: name '%s' addrs %08x %08x %08x %08x\n",
  171.             macHost.cname,
  172.             macHost.addr[0],macHost.addr[1],
  173.             macHost.addr[2],macHost.addr[3]);
  174. #endif
  175.  
  176.     /* was the 'name' an IP address? */
  177.     if (macHost.cname[0] == 0)
  178.     {
  179.         h_errno = HOST_NOT_FOUND;
  180.         return(NULL);
  181.     }
  182.     
  183.     /* for some reason there is a dot at the end of the name */
  184.     i = strlen(macHost.cname) - 1;
  185.     if (macHost.cname[i] == '.')
  186.         macHost.cname[i] = 0;
  187.     
  188.     for (i=0; i<NUM_ALT_ADDRS && macHost.addr[i]!=0; i++)
  189.     {
  190.         addrPtrs[i] = &macHost.addr[i];
  191.     }
  192.     addrPtrs[i] = NULL;
  193.     
  194.     return(&unixHost);
  195. }
  196.  
  197. struct hostent *
  198. gethostbyaddr(addrP,len,type)
  199.     ip_addr *addrP;
  200.     int len;
  201.     int type;
  202. {
  203. #pragma unused(len)
  204. #pragma unused(type)
  205.     Boolean done;
  206.     int i;
  207.     
  208. #if    NETDB_DEBUG >= 3
  209.     dprintf("gethostbyaddr: %08x\n",*addrP);
  210. #endif
  211.  
  212.     for (i=0; i<NUM_ALT_ADDRS; i++)
  213.         macHost.addr[i] = 0;
  214.     done = false;
  215.     if (AddrToName(*addrP,&macHost,DNRDone,&done) == cacheFault)
  216.     {
  217. #if NETDB_DEBUG >= 5
  218.         dprintf("gethostbyaddr: spinning\n");
  219. #endif
  220.         while(! done)
  221.         {
  222.             if (spinroutine != NULL)
  223.                 (*spinroutine)();
  224.         }
  225. #if NETDB_DEBUG >= 5
  226.         dprintf("gethostbyaddr: done spinning\n");
  227. #endif
  228.     }
  229.     switch (macHost.rtnCode)
  230.     {
  231.         case noErr: break;
  232.         
  233.         case cacheFault:    h_errno = NO_RECOVERY;        return(NULL);
  234.         case noNameServer:    h_errno = HOST_NOT_FOUND;    return(NULL);
  235.         case authNameErr:    h_errno = HOST_NOT_FOUND;    return(NULL);
  236.         case noAnsErr:        h_errno = TRY_AGAIN;        return(NULL);
  237.         case dnrErr:        h_errno = NO_RECOVERY;        return(NULL);
  238.         case outOfMemory:    h_errno = TRY_AGAIN;        return(NULL);
  239.         case notOpenErr:    h_errno = NO_RECOVERY;        return(NULL);
  240.         default:            h_errno = NO_RECOVERY;        return(NULL);
  241.     }
  242. #if NETDB_DEBUG >= 5
  243.     dprintf("gethostbyaddr: name '%s' addrs %08x %08x %08x %08x\n",
  244.             macHost.cname,
  245.             macHost.addr[0],macHost.addr[1],
  246.             macHost.addr[2],macHost.addr[3]);
  247. #endif
  248.     /* for some reason there is a dot at the end of the name */
  249.     i = strlen(macHost.cname) - 1;
  250.     if (macHost.cname[i] == '.')
  251.         macHost.cname[i] = 0;
  252.     
  253.     for (i=0; i<NUM_ALT_ADDRS; i++)
  254.     {
  255.         addrPtrs[i] = &macHost.addr[i];
  256.     }
  257.     addrPtrs[NUM_ALT_ADDRS] = NULL;
  258.     
  259.     return(&unixHost);
  260. }
  261.  
  262. char *
  263. inet_ntoa(inaddr)
  264.     ip_addr inaddr;
  265. {
  266.     (void) AddrToStr(inaddr,macHost.cname);
  267.     return(macHost.cname);
  268. }
  269.  
  270. ip_addr 
  271. inet_addr(address)
  272.     char *address;
  273. {
  274.     if (StrToAddr(address,&macHost,NULL,NULL) != noErr)
  275.         return((ip_addr)-1);
  276.     
  277. #if NETDB_DEBUG >= 5
  278.     dprintf("inet_addr: name '%s' addr %08x\n",
  279.             macHost.cname,macHost.addr[0]);
  280. #endif
  281.  
  282.     /* was the 'address' really a name? */
  283.     if (macHost.cname[0] != 0)
  284.         return((ip_addr)-1);
  285.     
  286.     return(macHost.addr[0]);
  287. }
  288.  
  289. /*
  290.  * gethostname()
  291.  *
  292.  * check _res_lhostname.  If it contains a host name, return it.
  293.  *
  294.  * Otherwise, get the host name from a name server, stuff it into 
  295.  * _res_lhostname for future use, and return it.
  296.  *
  297.  * The name server for the host name associated with our IP address 
  298.  * (which is determined from MacTCP).
  299.  *
  300.  * If I can't get a host name, I default the host name and use that 
  301.  * for ever after. 
  302.  */
  303.  
  304. #define DEFAULT_NAME    "mac_from_mars"    /* for want of anything better. */
  305. static Boolean needname = true;
  306. static char    _res_lhostname[MAXDNAME]; /* MAXDNAME from arpa/nameser.h */
  307.  
  308. gethostname( machname, buflen)
  309.     char *machname;
  310.     long buflen;
  311. {
  312.     ip_addr ipaddr;
  313.     struct hostent *hp;
  314.     
  315. #if    NETDB_DEBUG >= 3
  316.     dprintf("gethostname: \n");
  317. #endif
  318.  
  319.     if (needname) 
  320.     {
  321.         ipaddr = xIPAddr();
  322.         hp = gethostbyaddr( &ipaddr, sizeof(ip_addr), AF_INET);
  323.         if( hp == NULL)  
  324.             strcpy( _res_lhostname, DEFAULT_NAME);
  325.         else
  326.             strncpy( _res_lhostname, hp->h_name, buflen);
  327.         needname = false;
  328.     }
  329.     
  330.     /* Have name, return it. */
  331.     strncpy( machname, _res_lhostname, buflen);
  332.     machname[buflen-1] = 0;
  333.     return(0);
  334. }
  335.  
  336. /*
  337.  *    getdomainname()
  338.  *
  339.  *    Get default local domain.
  340.  */
  341. pascal void OneCache(cache,userdata)
  342.     struct cacheEntryRecord *cache;
  343.     char *userdata;
  344. {
  345. #pragma unused(userdata)
  346.     SysBeep(10);
  347.     dprintf("name '%s' type %d class %d ttl %d rdata %08x\n",
  348.             cache->cname,
  349.             cache->type,
  350.             cache->class,
  351.             cache->ttl,
  352.             cache->rdata);
  353. }
  354.  
  355. getdomainname(name,namelen)
  356.     char *name;
  357.     int namelen;
  358. {
  359. #pragma unused(name)
  360. #pragma unused(namelen)
  361.     OSErr io;
  362.     
  363. #if    NETDB_DEBUG >= 3
  364.     dprintf("getdomainname: \n");
  365. #endif
  366.  
  367.     io = EnumCache(OneCache,NULL);
  368.     if (io != noErr)
  369.         dprintf("EnumCache error %d",io);
  370. #if 0
  371.     res_getdomainname();
  372.     strncpy (name,_res.defdname, namelen);
  373. #endif
  374. }
  375.  
  376.  
  377. /*
  378.  *    getservbybname()
  379.  *
  380.  *    Real kludgy.  Should at least consult a resource file as the service
  381.  *    database.
  382.  */
  383. typedef struct services {
  384.     char        sv_name[12];
  385.     short        sv_number;
  386.     char        sv_protocol[5];
  387. } services_t, *services_p;
  388.  
  389. static    struct services    slist[] = 
  390.     {"echo", 7, "udp"},
  391.     {"discard", 9, "udp"},
  392.     {"time", 37, "udp"},
  393.     {"domain", 53, "udp"},
  394.     {"sunrpc", 111, "udp"},
  395.     {"tftp", 69, "udp"},
  396.     {"biff", 512, "udp"},
  397.     {"who", 513, "udp"},
  398.     {"talk", 517, "udp"},
  399.     {"route", 520, "udp"},
  400.     {"new-rwho", 550, "udp"},
  401.     {"netstat", 15, "tcp"},
  402.     {"ftp-data", 20, "tcp"},
  403.     {"ftp", 21, "tcp"},
  404.     {"telnet", 23, "tcp"},
  405.     {"smtp", 25, "tcp"},
  406.     {"time", 37, "tcp"},
  407.     {"whois", 43, "tcp"},
  408.     {"domain", 53, "tcp"},
  409.     {"hostnames", 101, "tcp"},
  410.     {"nntp", 119, "tcp"},
  411.     {"finger", 79, "tcp"},
  412.     {"uucp-path", 117, "tcp"},
  413.     {"untp", 119, "tcp"},
  414.     {"ntp", 123, "tcp"},
  415.     {"exec", 512, "tcp"},
  416.     {"login", 513, "tcp"},
  417.     {"shell", 514, "tcp"},
  418.     {"printer", 515, "tcp"},
  419.     {"courier", 530, "tcp"},
  420.     {"uucp", 540, "tcp"},
  421.     {"", 0, "" }
  422. };
  423.                      
  424. #define    MAX_SERVENT            10
  425. static     struct servent        servents[MAX_SERVENT];
  426. static     int                    servent_count=0;
  427.  
  428. struct servent *
  429. getservbyname (name, proto)
  430. char        *name, *proto;
  431. {
  432.     int                i;
  433.     struct    servent    *se;
  434.     
  435.     if (strcmp (proto, "udp") == 0 || strcmp (proto, "tcp") == 0) 
  436.     {
  437.         for (i=0; slist[i].sv_number != 0; i++)
  438.             if (strcmp (slist[i].sv_name, name) == 0)
  439.                 if (strcmp (slist[i].sv_protocol, proto) == 0) 
  440.                 {
  441.                     se = &servents[servent_count];
  442.                     se->s_name = slist[i].sv_name;
  443.                     se->s_aliases = NULL;
  444.                     se->s_port = slist[i].sv_number;
  445.                     se->s_proto = slist[i].sv_protocol;
  446.                     servent_count = (servent_count +1) % MAX_SERVENT;
  447.                     return (se);
  448.                 }
  449.         return (NULL);
  450.     }
  451.     else 
  452.     {
  453.         errno = EPROTONOSUPPORT;
  454.         return(NULL);
  455.     }
  456. }
  457.  
  458. static    char    tcp[] = "tcp";
  459. static    char    udp[] = "udp";
  460. #define    MAX_PROTOENT            10
  461. static     struct protoent        protoents[MAX_PROTOENT];
  462. static     int                    protoent_count=0;
  463. struct protoent *
  464. getprotobyname (name)
  465. char        *name;
  466. {
  467.     struct protoent *pe;
  468.     
  469.     pe = &protoents[protoent_count];
  470.     if (strcmp (name, "udp") == 0) 
  471.     {
  472.         pe->p_name = udp;
  473.         pe->p_proto = IPPROTO_UDP;
  474.     }
  475.     else if (strcmp (name, "tcp") == 0) 
  476.     {
  477.         pe->p_name = tcp;
  478.         pe->p_proto = IPPROTO_TCP;
  479.     }
  480.     else 
  481.     {    
  482.         errno = EPROTONOSUPPORT;
  483.         return(NULL);
  484.     }
  485.     pe->p_aliases = NULL;
  486.     protoent_count = (protoent_count +1) % MAX_PROTOENT;
  487.     return (pe);
  488. }
  489.  
  490. char *h_errlist[] = 
  491. {
  492.     "Error 0",
  493.     "Unknown host",                        /* 1 HOST_NOT_FOUND */
  494.     "Host name lookup failure",            /* 2 TRY_AGAIN */
  495.     "Unknown server error",                /* 3 NO_RECOVERY */
  496.     "No address associated with name",    /* 4 NO_ADDRESS */
  497. };
  498. int    h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
  499.  
  500.